#include "chunkmanager.h"

ChunkManager::ChunkManager()
{
    for(int i=0;i<X_CHUNKS;i++)
        for(int j=0;j<Y_CHUNKS;j++)
            for(int k=0;k<Z_CHUNKS;k++){
                getChunkFromPt(MUL_CHNKSIZE(i),MUL_CHNKSIZE(j),MUL_CHNKSIZE(k))
                        .setWorldCoords(MUL_CHNKSIZE(i),MUL_CHNKSIZE(j),MUL_CHNKSIZE(k));//optimize later
                getChunkFromPt(MUL_CHNKSIZE(i),MUL_CHNKSIZE(j),MUL_CHNKSIZE(k))
                        .initVBO();
            }
}

Chunk& ChunkManager::getChunkFromPt(int x, int y, int z){
     return carr[ vector_to_index( x, y, z ) ];
}

inline int ChunkManager::vector_to_index(int x, int y, int z) const{
    return MUL_ZCHNK(MUL_YCHNK(DIV_CHNKSIZE(x))) + MUL_ZCHNK(DIV_CHNKSIZE(y)) + DIV_CHNKSIZE(z); //optimize later
}

 voxel& ChunkManager::getVoxel(int x, int y, int z){
     if(!isValid(x,y,z))throw "bad voxel";
     return getChunkFromPt(x,y,z).getChunkVoxel( x, y, z );
 }

 void ChunkManager::addVoxel(int x, int y, int z, voxel& v){
     if(isValid(x,y,z)){
         v.setFace(0);
         removeHiddenFaces(x,y,z,v);
         getChunkFromPt(x,y,z).addChunkVoxel( x, y, z, v );
     }
 }

 void ChunkManager::removeVoxel(int x, int y, int z){
     if(isValid(x,y,z)){
         restoreHiddenFaces(x,y,z);
         getChunkFromPt(x,y,z).removeChunkVoxel( x, y, z );
     }
}

 void ChunkManager::setVoxelColor(int x, int y, int z, colour& c){
     if(isValid(x,y,z))
        getChunkFromPt(x,y,z).setVoxelColor(x,y,z,c);
 }

 Chunk& ChunkManager::operator [](int index){
     return carr[index];
 }

 bool ChunkManager::isValid(int x, int y, int z){
     if(x>=0 && x<max_x &&
        y>=0 && y<max_y &&
        z>=0 && z<max_z)return true;
     return false;
 }

 int ChunkManager::Size(){
     return size;
 }

 void ChunkManager::removeHiddenFaces(int x, int y, int z,voxel &v){
     if(y+1<max_y){
         if(!getVoxel(x,y+1,z).draw())v.setDrawTop(true);
         else getVoxel(x,y+1,z).setDrawBottom(false);
     }else v.setDrawTop(true);

     if(y-1>=0){
         if(!getVoxel(x,y-1,z).draw())v.setDrawBottom(true);
         else getVoxel(x,y-1,z).setDrawTop(false);
     }else v.setDrawBottom(true);

     if(x+1<max_x){
         if(!getVoxel(x+1,y,z).draw())v.setDrawRight(true);
         else getVoxel(x+1,y,z).setDrawLeft(false);
     }else v.setDrawRight(true);

     if(x-1>=0){
         if(!getVoxel(x-1,y,z).draw())v.setDrawLeft(true);
         else getVoxel(x-1,y,z).setDrawRight(false);
     }else v.setDrawLeft(true);

     if(z+1<max_z){
         if(!getVoxel(x,y,z+1).draw())v.setDrawFront(true);
         else getVoxel(x,y,z+1).setDrawBack(false);
     }else v.setDrawFront(true);

     if(z-1>=0){
         if(!getVoxel(x,y,z-1).draw())v.setDrawBack(true);
         else getVoxel(x,y,z-1).setDrawFront(false);
     }else v.setDrawBack(true);
 }

 void ChunkManager::restoreHiddenFaces(int x, int y, int z){
     // to do: update neighbour chunks that are affected
     if(y+1<max_y && getVoxel(x,y+1,z).draw())
          getVoxel(x,y+1,z).setDrawBottom(true);

     if(y-1>=0 && getVoxel(x,y-1,z).draw())
         getVoxel(x,y-1,z).setDrawTop(true);

     if(x+1<max_x && getVoxel(x+1,y,z).draw())
         getVoxel(x+1,y,z).setDrawLeft(true);

     if(x-1>=0 && getVoxel(x-1,y,z).draw())
         getVoxel(x-1,y,z).setDrawRight(true);

     if(z+1<max_z && getVoxel(x,y,z+1).draw())
         getVoxel(x,y,z+1).setDrawBack(true);


     if(z-1>=0 && getVoxel(x,y,z-1).draw())
         getVoxel(x,y,z-1).setDrawFront(true);
 }
